<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        @font-face {
            font-family: LCD;
            font-style: normal;
            font-weight: 400;
            src: url("./fonts/LCDWinTT/LCD-N___.TTF");
        }
        #box{
            margin-top: 20px;
            font-family: LCD;
            font-size: 100px;
        }
    </style>
</head>
<body>
    <button onclick="cuountor.start()">开始</button>
    <button onclick="cuountor.pause()">暂停</button>
    <button onclick="cuountor.resume()">继续</button>
    <button onclick="cuountor.reset()">重置</button>
    <div id="box"></div>
    <script>
        // y = kx + b;
        function countUp(selector, options) {
            const el = document.querySelector(selector);
            let { from, to, deci = 2, duration = 3000, prefix = '', suffix = '' } = options;
            // 斜率公式: (y2-y1)/(x2-x1) => 就是tan@
            // 第一个点坐标： x轴时间为0时，y值是from(1)
            // 第二个点坐标： x轴时间为duration(3000ms)时，y值是to(100)
            // 斜率公式几何意义：三角形的tan@ = 对边：邻边
            const k = (to - from)/duration;
            // 小数点保留多少位
            const deciFn = (value, deciNum = 2) => {
                const baseNum = Math.pow(10, deciNum);
                return (Math.round(value * baseNum) / baseNum).toFixed(deciNum);
            }
            el.textContent = prefix + deciFn(from, deci) + suffix;
            let beginTime;
            let frameId = null;
            let time = 0;
            let curValue = from;
            const run = (prevTime = 0) => {
                cancelAnimationFrame(frameId);
                frameId = requestAnimationFrame(() => {
                    const lastNow = +new Date();
                    time = lastNow - beginTime;
                    // y = kx + b
                    const value = k * time + curValue;
                    if(k > 0) {
                        if(value >= to) {
                            el.textContent = prefix+ to.toFixed(deci) + suffix;
                            return
                        }
                    }else {
                        if(value <= to) {
                            el.textContent = prefix+ to.toFixed(deci) + suffix;
                            return
                        }
                    } 
                    el.textContent = prefix+ deciFn(value, deci) + suffix;
                    run();
                });
            };
            const cuountor = {
                // 开始
                start() {
                    this.reset();
                    run();
                },
                // 暂停
                pause() {
                    frameId && cancelAnimationFrame(frameId);
                },
                // 继续
                resume() {
                    if(!frameId) {return}
                    beginTime = +new Date();
                    // 相当于重新开始一次，此时的from等于暂停时的值
                    curValue = k * time + curValue;
                    run();
                },
                // 重置
                reset() {
                    // 暂停之前的动画
                    this.pause();
                    beginTime = +new Date();
                    frameId = null;
                    time = 0;
                    curValue = from;
                    el.textContent = prefix + deciFn(from, deci) + suffix;
                }
            };
            return cuountor
        }
        const cuountor = countUp('#box', { from: 100, to: 1 });
    </script>
</body>
</html>